﻿/*修改历史：
 *
 *
 * 作者：mashanlin  m.sh.lin0328@163.com
 * 版本：V1.2
 * 完成日期：2013-4-20
 */
using System;
using System.IO;

namespace MSL.Utility.IO
{
    /// <summary>
    /// 日志记录的类型
    /// </summary>
    public enum LogType : int
    {
        /// <summary>
        /// 程序错误
        /// </summary>
        ApplicationError = -1,
        /// <summary>
        /// 系统错误
        /// </summary>
        SysError,
        /// <summary>
        /// 常规操作
        /// </summary>
        Common,
        /// <summary>
        /// 安装操作
        /// </summary>
        Setup,
        /// <summary>
        /// 登陆
        /// </summary>
        Login,
        /// <summary>
        /// 退出
        /// </summary>
        Logout,
        /// <summary>
        /// 未知
        /// </summary>
        UnKnown,
        /// <summary>
        /// 无
        /// </summary>
        None
    }
    /// <summary>
    /// 日志等级
    /// </summary>
    public enum LogWarnLevel
    {
        /// <summary>
        /// 日常等级
        /// </summary>
        message = 1,
        /// <summary>
        /// 错误等级
        /// </summary>
        Error = 2
    }
    /// <summary>
    /// 简单的日志文件操作类
    /// </summary>
    public class Log : IDisposable
    {
        #region 变量/属性

        private static String _logPath = System.Configuration.ConfigurationManager.AppSettings["LogPath"];
        private static Int32 _logSize = 10240;//KB
        private static Int32 _maxCount = 10;
        private static String _logSuffix = "log";
        private static Int32 _linecharCount = 120;
        private static FileStream _newFS = null;
        private static FileInfo _openFile = null;
        private static StreamWriter _sw = null;
        /// <summary>
        /// 存放路径
        /// </summary>
        public static string LogPath
        {
            get { return _logPath; }
            set
            {
                if (String.IsNullOrEmpty(_logPath))
                {
                    _logPath = System.Configuration.ConfigurationManager.AppSettings["LogPath"] + "/Log";
                }
                CreateMatchFolder(_logPath);
            }
        }
        /// <summary>
        /// 每个日志文件大小(kb)
        /// </summary>
        public static int LogSize
        {
            get { return _logSize; }
            set { _logSize = value; }
        }
        /// <summary>
        /// 每天日志文件最大记录数量
        /// </summary>
        public static int MaxCount
        {
            get { return _maxCount; }
            set { _maxCount = value; }
        }
        /// <summary>
        /// 日志文件后缀名
        /// </summary>
        public static string LogSuffix
        {
            get { return _logSuffix; }
            set { _logSuffix = value; }
        }
        /// <summary>
        /// 行字数,默认120
        /// </summary>
        public static int LineCharCount
        {
            get { return _linecharCount; }
            set { _linecharCount = value; }
        }
        #endregion

        #region 日常日志
        /// <summary>
        /// 日常日志
        /// </summary>
        /// <param name="title">标题</param>
        /// <param name="message">内容</param>
        public static bool SaveLog(string title, string message)
        {
            return WriteLog(LogType.Common, _logPath, title, LogWarnLevel.message, message);
        }
        /// <summary>
        /// 日常日志
        /// </summary>
        /// <param name="logType">日志类型</param>
        /// <param name="title">标题</param>
        /// <param name="message">内容</param>
        public static bool SaveLog(LogType logType, string title, string message)
        {
            return WriteLog(logType, _logPath, title, LogWarnLevel.message, message);
        }
        /// <summary>
        ///  日常日志
        /// </summary>
        /// <param name="logType">日志类型</param>
        /// <param name="title">标题</param>
        /// <param name="message">内容</param>
        /// <param name="autoLinefeed">是否自动换行</param>
        /// <returns></returns>
        public static bool SaveLog(LogType logType, string title, string message, bool autoLinefeed)
        {
            string[] newinfo = SplitString(message);
            return WriteLog(logType, _logPath, title, LogWarnLevel.message, newinfo);
        }
        #endregion

        #region 错误日志

        /// <summary>
        /// 错误日志
        /// </summary>
        /// <param name="title">标题</param>
        /// <param name="ex">内容</param>
        public static bool SaveErrorLog(string title, Exception ex)
        {
            return WriteLog(LogType.ApplicationError, _logPath, title, LogWarnLevel.Error, ex.Message);
        }
        /// <summary>
        /// 错误日志
        /// </summary>
        /// <param name="title">标题</param>
        /// <param name="ex">内容</param>
        /// <param name="autoLinefeed">是否自动换行</param>
        /// <returns></returns>
        public static bool SaveErrorLog(string title, Exception ex, bool autoLinefeed)
        {
            string[] newinfo = SplitString(ex.Message);
            return WriteLog(LogType.ApplicationError, _logPath, title, LogWarnLevel.Error, newinfo);
        }
        #endregion

        #region 私有方法
        /// <summary>
        /// 创建日志文件夹
        /// </summary>
        /// <param name="path"></param>
        private static void CreateMatchFolder(string path)
        {
            if (!Directory.Exists(_logPath))
            {
                Directory.CreateDirectory(path);
            }
        }
        private static string[] SplitString(string message)
        {
            int charLen = message.Length;
            int line = (int)Math.Ceiling((charLen / (double)_linecharCount));
            string[] splitArray = new string[line];//行数
            for (int i = 0; i < line; i++)
            {
                if (charLen < _linecharCount)
                {
                    splitArray[i] = message;
                }
                else if ((charLen - (i * _linecharCount)) < _linecharCount)
                {
                    splitArray[i] = message.Substring(i * _linecharCount, charLen - (i * _linecharCount));
                }
                else
                {
                    splitArray[i] = message.Substring(i * _linecharCount, _linecharCount);
                }
            }
            return splitArray;
        }

        /// <summary>
        /// 写入日志
        /// </summary>
        /// <param name="path">日志文件路径 如:D:/log</param>
        /// <param name="title">标题</param>
        /// <param name="level">日志等级</param>
        /// <param name="message">信息</param>
        /// <returns>是否写入成功</returns>
        private static bool WriteLog(LogType type, string path, string title, LogWarnLevel level, params string[] message)
        {
            string logName = String.Format("{0}.{1}", DateTime.Now.ToString("yyyy-MM-dd"), _logSuffix);
            if (type != 0)
            {
                logName = Enum.Parse(typeof(LogType), type.GetHashCode().ToString()).ToString().Trim() + String.Format("{0}.{1}", DateTime.Now.ToString("yyyy-MM-dd"), _logSuffix);
            }
            string logFile = String.Format("{0}/{1}", path, logName);
            if (!File.Exists(logFile))
            {
                CreateNewLog(logFile);
            }
            if (_openFile == null || _sw == null)
            {
                _openFile = new FileInfo(logFile);
                long sizeKB = (_openFile.Length / 1024);
                if (sizeKB > _logSize)
                {
                    logFile = FindCanWriteFileName(path, logName);
                    CreateNewLog(logFile);
                    _openFile = new FileInfo(logFile);
                }
                _newFS = _openFile.Open(FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
                _sw = new StreamWriter(_newFS);
            }

            if (_sw == null) return false;
            _sw.WriteLine("================{0}=================", title);
            _sw.WriteLine("记录时间:{0}  等级:{1}", DateTime.Now.ToString(), level == LogWarnLevel.message ? "message" : "error");
            _sw.WriteLine();
            if (message != null)
            {
                foreach (string str in message)
                {
                    _sw.WriteLine(str);
                }
            }
            _sw.WriteLine();
            _sw.Flush();
            return true;

        }

        /// <summary>
        /// 建立一个新日志文件
        /// </summary>
        /// <param name="logFile"></param>
        private static void CreateNewLog(string logFile)
        {
            if (!File.Exists(logFile))
            {
                using (_newFS = new FileStream(logFile, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.ReadWrite))
                {
                    _sw = new StreamWriter(_newFS, System.Text.Encoding.UTF8);
                    _sw.WriteLine("文件创建时间:{0}", DateTime.Now.ToString());
                    _sw.WriteLine("文件最大记录大小:{0}KB(与实际可能会有出入)", _logSize);
                    _sw.WriteLine(_sw.NewLine);
                    _newFS.Flush();
                    _sw.Dispose();
                    _sw = null;
                }
            }
        }

        /// <summary>
        /// 寻找一个当天可写的文件,并且不大于设置的文件大小
        /// </summary>
        /// <param name="path">日志存放路径 如:D:/log</param>
        /// <param name="name"></param>
        /// <returns></returns>
        private static string FindCanWriteFileName(string path, string name)
        {
            string newName = string.Empty;
            long sizeKB = 0;
            FileInfo tempFi = null;
            for (int i = 1; i <= MaxCount; i++)
            {
                newName = String.Format("{0}/{2}-{1}", path, name, i);
                if (!File.Exists(newName))
                {
                    break;
                }
                else
                {
                    tempFi = new FileInfo(newName);
                    sizeKB = (tempFi.Length / 1024);
                    if (sizeKB < _logSize)
                    {
                        break;
                    }
                }
            }
            tempFi = null;
            return newName;
        }
        #endregion

        #region Dispose

        private bool disposed = false;

        /// <summary>
        /// 垃圾回收器执行函数
        /// </summary>
        ~Log()
        {
            //如果有就释放非托管
            Dispose(false);
        }

        /// <summary>
        /// 关闭并释放资源
        /// </summary>
        public void Dispose()
        {
            //全部释放
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        /// <summary>
        /// 关闭并释放资源
        /// </summary>
        public void Close()
        {
            Dispose();
        }

        /// <summary>
        /// 关闭并释放资源
        /// </summary>
        protected virtual void Dispose(bool disposing)
        {
            if (disposed)
            {
                return;
            }
            // 清理托管资源
            if (disposing)
            {
                if (_sw != null)
                {
                    _sw.Close();
                    _sw.Dispose();
                    _sw = null;
                }
                if (_newFS != null)
                {
                    _newFS.Close();
                    _newFS.Dispose();
                    _newFS = null;
                }

                if (_openFile != null)
                {
                    _openFile = null;
                }
            }
            //非托管
            disposed = true;
        }

        #endregion
    }
}